/*
 * Unicast.cpp
 *
 *  Created on: 08/ott/2013
 *      Author: alessandrob
 */
#include<iostream>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<opencv2/opencv.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/highgui/highgui.hpp>
#include "Utility.h"
#define BUFLEN 1400
#define PORT 5002
#define PORTB 5003
using namespace std;
using namespace cv;

void unicast(int threshold)
{
	cout<<"Setting up TCP client..."<<endl;
	struct sockaddr_in server_address;
	char ack='f';
	char infoPacket[9];
	int sockfd,dataReceived,i;
	int dataSent;
	char last;
	Mat picture;
	double det_time;
	Mat descriptors;
	vector<KeyPoint> kp;

	Ptr<FeatureDetector> detector;
	detector = new BRISK(threshold,4);
	Ptr<DescriptorExtractor> descriptorExtractor;
	descriptorExtractor = new BRISK(threshold,4);

	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))==-1)
		printErrorLog("Client socket not created correctly.");
	cout<<"Client TCP socket created correctly."<<endl;
	bzero(&server_address, sizeof(server_address));
	server_address.sin_family = AF_INET;
	server_address.sin_port = htons(PORT);
	char ip[16];
	memmove(ip,"10.42.0.5",sizeof(ip));
	if(inet_aton(ip,&server_address.sin_addr)==0)
		printErrorLog("IP address not correct");
	cout<<"Ready for the connection..."<<endl;
	//unsigned int slen=sizeof(server_address);
	//int time = 1;
	//if(setsockopt(sockfd,SOL_SOCKET,SO_TIMESTAMP,(void*)&time,sizeof(time))<0)
	//	printErrorLog("out");
	int CPUspeed;
	if(connect(sockfd,(const struct sockaddr*)&server_address,sizeof(server_address))<0)
		printErrorLog("Connection refused");
	if ((dataSent = send(sockfd, &CPUspeed, sizeof(int), 0))==-1)
		printErrorLog("Cpu speed not sent correctly");
	//char ready = 'r';
	//if (sendto(sockfd, &ready, sizeof(char), 0, (struct sockaddr*)&server_address, slen)==-1)
	//	printErrorLog("Connection request failed");
	cout<<"Client correctly connected. Setting up iperf server..."<<endl;
	//Setting up iperf server
	char command[12];
	strcpy(command,"iperf -s -D >/home/ubuntu/serverLog.txt");
	//system(command);
	int cols,rows;
	vector<int> params = vector<int>(2);
	//Waiting for the server synchronization
	char sync;
	cout<<"Waiting for the synchronization"<<endl;
	if(recv(sockfd,&sync,sizeof(char),0)==-1)
		printErrorLog("Synchronization failed");
	//cout<<"Synchronization: done."<<endl;
	if(sync=='s')
	{
		//Setting up local timer
		cout<<"Client synchronized. Timer started"<<endl;
		det_time=(double)getTickCount();
		//Waiting for the image size
		if(recv(sockfd,&infoPacket[0],sizeof(char)*9,0)!=sizeof(char)*9)
			printErrorLog("Info packet not received correctly.");
		cols = (infoPacket[0] << 24);
		cols = cols + (infoPacket[1] << 16);
		cols = cols + (infoPacket[2] << 8);
		cols = cols + (infoPacket[3]);
		rows = (infoPacket[4] << 24);
		rows = rows + (infoPacket[5] << 16);
		rows = rows + (infoPacket[6] << 8);
		rows = rows + (infoPacket[7]);
		last = infoPacket[8];
		double cols_time = ((double)getTickCount()-det_time)/getTickFrequency();
		cout<<"Receiving info packet time: T+"<<cols_time*1000<<"ms"<<endl;
		uchar imageArray[cols*rows];
		double starttime = ((double)getTickCount()-det_time)/getTickFrequency();
		cout<<"Ready for receiving data. Time: T+"<<starttime*1000<<"ms"<<endl;
		dataReceived = recv(sockfd,&imageArray[0],cols*rows,MSG_WAITALL);
		double receivingtime = ((double)getTickCount()-det_time)/getTickFrequency();
		cout<<"Receiving time: T+"<<receivingtime*1000<<"ms"<<endl;
		if(dataReceived!=cols*rows)
			printErrorLog("Data not received correctly");
		cout<<"Data correctly received"<<endl;
		//Sending ACK if I am the last client
		if(last==1)
		{
			if(send(sockfd, &ack , sizeof(char), 0)!=sizeof(char))
				printErrorLog("ACK not sent correctly");
			cout<<"ACK sent correctly"<<endl;
			double ack_time = ((double)getTickCount()-det_time)/getTickFrequency();
			cout<<"ACK time: T+"<<ack_time*1000<<"ms"<<endl;
		}
		picture = Mat(rows,cols,CV_8UC1,imageArray,cols);
		double openingtime = ((double)getTickCount()-det_time)/getTickFrequency();
		cout<<"Opening time: T+"<<openingtime*1000<<"ms"<<endl;

		//Compute BRISK
		double sum=0;
		int size;
		//for(i=0;i<10;i++)
		//{
		det_time=(double)getTickCount();
		detector->detect(picture,kp);
		Mat distributedKp;
		//drawKeypoints(picture,kp,distributedKp);
		//imwrite("/home/ubuntu/distributedKP.jpg",distributedKp,params);
		descriptorExtractor->compute(picture,kp,descriptors);
		//BRISKD.detect(picture,kp);
		//BRISKD.compute(picture,kp,descriptors);
		det_time=((double)getTickCount()-det_time)/getTickFrequency();
		//if(i!=0)
		//	sum=sum+det_time;
		size = kp.size();


			//cout<<size<<endl;
		//}
		//cout<<"Processing time: "<<(sum/9)*1000<<"ms"<<endl;
		double totaltime = (openingtime+(sum/9))*1000;
		//cout<<"Total time: T+"<<totaltime<<"ms"<<endl;
		cout<<"Keypoints detected: "<<size<<endl;
		vector<int> params = vector<int>(1);
		params[0]=0;
		//imwrite("/home/ubuntu/imageClient.jpg",picture,params);
		//char request;
		cout<<"SENDING DATA TO THE SERVER..."<<endl;
		sendData(sockfd,totaltime,size,kp,descriptors);
	}
	//}
	//Mat distributedKp;
	//drawKeypoints(picture,kp,distributedKp);
	//imwrite("/home/ubuntu/distributedKP.jpg",distributedKp,params);
	close(sockfd);
}


